package org.kl.bpm.operation;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.kl.bf.utils.ApplicationContextHelper;
import org.kl.bpm.entity.conf.BpmConfForm;
import org.kl.bpm.entity.conf.BpmFormTemplate;
import org.kl.bpm.entity.conf.BpmKvProp;
import org.kl.bpm.entity.conf.BpmKvRecord;
import org.kl.bpm.service.conf.BpmConfFormService;
import org.kl.bpm.service.conf.BpmFormTemplateService;
import org.kl.bpm.service.conf.BpmKvRecordService;
import org.kl.bpm.support.FormInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springside.modules.mapper.JsonMapper;

/**
 * 退回
 * @author QJ
 * @date 2014年10月13日
 */
public class RollbackTaskOperation extends AbstractOperation<Void> {
	private static Logger logger = LoggerFactory.getLogger(RollbackTaskOperation.class);
	public static final String FORM_FIELD_NAME_VARIABLE = "${nodeName}";
	public static final String OPERATION_TASK_ID = "taskId";
	public static final String OPERATION_COMMENT = "退回";
	public static final int STATUS_DRAFT_PROCESS = 0;
	public static final int STATUS_DRAFT_TASK = 1;
	public static final int STATUS_RUNNING = 2;
	private JsonMapper jsonMapper = new JsonMapper();
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Void execute(CommandContext commandContext) {
		ProcessEngine processEngine = getProcessEngine();
		BpmFormTemplateService bpmFormTemplateService = getBpmFormTemplateService();
		BpmKvRecordService bpmKvRecordService = getBpmKvRecordService();
		BpmConfFormService bpmConfFormService = getBpmConfFormService();
		String taskId = getParameter(OPERATION_TASK_ID);
		HistoryService historyService = processEngine.getHistoryService();
		RuntimeService runtimeService = processEngine.getRuntimeService();
		RepositoryService repositoryService = processEngine.getRepositoryService();
		TaskService taskService = processEngine.getTaskService();
		// 取得当前任务
        HistoricTaskInstance currTask = historyService
                .createHistoricTaskInstanceQuery().taskId(taskId)
                .singleResult();
        // 取得流程实例
        ProcessInstance instance = runtimeService
                .createProcessInstanceQuery()
                .processInstanceId(currTask.getProcessInstanceId())
                .singleResult();
        if (instance == null) {          
        	logger.error("流程已经结束");
        	throw new IllegalStateException("流程已经结束");
        }
        Map<String, Object> variables;
        variables = instance.getProcessVariables();
        // 取得流程定义
        ProcessDefinitionEntity definition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(currTask
                        .getProcessDefinitionId());
        if (definition == null) {          
            logger.error("流程定义未找到");
            throw new IllegalStateException("流程定义未找到");
        }
        FormService formService = processEngine.getFormService();
		String taskFormKey = formService.getTaskFormKey(currTask.getProcessDefinitionId(), currTask.getTaskDefinitionKey());
		FormInfo formInfo = new FormInfo();
		formInfo.setTaskId(taskId);
		formInfo.setFormKey(taskFormKey);

		// 尝试根据表单里字段的类型，进行转换
		Map<String, String> formTypeMap = new HashMap<String, String>();
		// 尝试根据表单里字段的类型，进行转换
		Map<String, String> fieldLabelMap = new HashMap<String, String>();

		BpmConfForm bpmConfForm = bpmConfFormService.findByBpmConfNodeBpmConfBaseProcessDefinitionIdAndBpmConfNodeCode(
				currTask.getProcessDefinitionId(), currTask.getTaskDefinitionKey());
		BpmFormTemplate formTemplate = bpmFormTemplateService.getBpmFormTemplate(bpmConfForm.getValue());
		if (formTemplate != null) {
			String content = formTemplate.getContent();
			content = StringUtils.replace(content, FORM_FIELD_NAME_VARIABLE, currTask.getTaskDefinitionKey());// 将表单中${nodeName}用节点定义KEY替换
			Map map = jsonMapper.fromJson(content, Map.class);
			if (map != null) {
				List<Map> list = (List<Map>) map.get("fields");
				for (Map item : list) {
					formTypeMap.put((String) item.get("name"), (String) item.get("type"));
					fieldLabelMap.put((String) item.get("name"), (String) item.get("label"));
				}
			}
		}
		String processInstanceId = currTask.getProcessInstanceId();
		BpmKvRecord record = bpmKvRecordService.findByRef(processInstanceId);
		Map<String, Object> processParameters = new HashMap<String, Object>();

		// 如果有表单，就从数据库获取数据
		for (BpmKvProp prop : record.getBpmKvProps()) {
			String key = prop.getCode();
			String value = prop.getValue();
			String formType = this.getFormType(formTypeMap, key);

			if ("userPicker".equals(formType)) {
				processParameters.put(key, new ArrayList(Arrays.asList(value.split(","))));
			} else if (formType != null) {
				processParameters.put(key, value);
				prop.setType(RecordBuilder.user_task_data);
				prop.setTaskId(taskId);
				prop.setFieldLabel(this.getFormType(fieldLabelMap, key));// 获取FieldLabel
				prop.setTaskDefinitionKey(currTask.getTaskDefinitionKey());
			}
		}
        // 取得上一步活动
        ActivityImpl currActivity = ((ProcessDefinitionImpl) definition)
                .findActivity(currTask.getTaskDefinitionKey());
        List<PvmTransition> nextTransitionList = currActivity
                .getIncomingTransitions();
        // 清除当前活动的出口
        List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
        List<PvmTransition> pvmTransitionList = currActivity
                .getOutgoingTransitions();
        for (PvmTransition pvmTransition : pvmTransitionList) {
            oriPvmTransitionList.add(pvmTransition);
        }
        pvmTransitionList.clear();
        // 建立新出口
        List<TransitionImpl> newTransitions = new ArrayList<TransitionImpl>();
        for (PvmTransition nextTransition : nextTransitionList) {
            PvmActivity nextActivity = nextTransition.getSource();
            ActivityImpl nextActivityImpl = ((ProcessDefinitionImpl) definition)
                    .findActivity(nextActivity.getId());
            TransitionImpl newTransition = currActivity
                    .createOutgoingTransition();
            newTransition.setDestination(nextActivityImpl);
            newTransitions.add(newTransition);
        }
        // 完成任务
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(instance.getId())
                .taskDefinitionKey(currTask.getTaskDefinitionKey()).list();
        for (Task task : tasks) {
            taskService.complete(task.getId(), variables);
            historyService.deleteHistoricTaskInstance(task.getId());
        }
        // 恢复方向
        for (TransitionImpl transitionImpl : newTransitions) {
            currActivity.getOutgoingTransitions().remove(transitionImpl);
        }
        for (PvmTransition pvmTransition : oriPvmTransitionList) {
            pvmTransitionList.add(pvmTransition);
        }
        record = new RecordBuilder().build(record, STATUS_RUNNING, processInstanceId);
		bpmKvRecordService.saveBpmKvRecord(record);
        return null;
	}
	
	/**
	 * 工具方法，获取表单的类型.
	 */
	private String getFormType(Map<String, String> formTypeMap, String name) {
		if (formTypeMap.containsKey(name)) {
			return formTypeMap.get(name);
		} else {
			return null;
		}
	}

	public BpmFormTemplateService getBpmFormTemplateService() {
		return ApplicationContextHelper.getBean(BpmFormTemplateService.class);
	}

	public BpmConfFormService getBpmConfFormService() {
		return ApplicationContextHelper.getBean(BpmConfFormService.class);
	}

	public BpmKvRecordService getBpmKvRecordService() {
		return ApplicationContextHelper.getBean(BpmKvRecordService.class);
	}
}
